package com.example.artemis.statistics;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 时间窗口统计模型
 * 用于统计特定时间窗口内的消息处理情况
 */
public class TimeWindowStatistics {

    private final LocalDateTime windowStart;
    private final LocalDateTime windowEnd;
    private final long windowSizeMinutes;

    // 统计数据
    private final AtomicInteger messageCount = new AtomicInteger(0);
    private final AtomicInteger successCount = new AtomicInteger(0);
    private final AtomicInteger failureCount = new AtomicInteger(0);
    private final AtomicLong totalProcessingTime = new AtomicLong(0);
    private final AtomicLong minProcessingTime = new AtomicLong(Long.MAX_VALUE);
    private final AtomicLong maxProcessingTime = new AtomicLong(0);

    public TimeWindowStatistics(LocalDateTime windowStart, long windowSizeMinutes) {
        this.windowStart = windowStart;
        this.windowSizeMinutes = windowSizeMinutes;
        this.windowEnd = windowStart.plus(windowSizeMinutes, ChronoUnit.MINUTES);
    }

    /**
     * 获取窗口开始时间
     */
    public LocalDateTime getWindowStart() {
        return windowStart;
    }

    /**
     * 获取窗口结束时间
     */
    public LocalDateTime getWindowEnd() {
        return windowEnd;
    }

    /**
     * 获取窗口大小（分钟）
     */
    public long getWindowSizeMinutes() {
        return windowSizeMinutes;
    }

    /**
     * 检查指定时间是否在窗口内
     */
    public boolean isInWindow(LocalDateTime time) {
        return !time.isBefore(windowStart) && !time.isAfter(windowEnd);
    }

    /**
     * 增加消息计数
     */
    public void incrementMessageCount() {
        messageCount.incrementAndGet();
    }

    /**
     * 增加成功计数
     */
    public void incrementSuccessCount() {
        successCount.incrementAndGet();
    }

    /**
     * 增加失败计数
     */
    public void incrementFailureCount() {
        failureCount.incrementAndGet();
    }

    /**
     * 增加处理时间
     */
    public void addProcessingTime(long time) {
        totalProcessingTime.addAndGet(time);
        updateMinProcessingTime(time);
        updateMaxProcessingTime(time);
    }

    /**
     * 获取消息总数
     */
    public int getMessageCount() {
        return messageCount.get();
    }

    /**
     * 获取成功数
     */
    public int getSuccessCount() {
        return successCount.get();
    }

    /**
     * 获取失败数
     */
    public int getFailureCount() {
        return failureCount.get();
    }

    /**
     * 获取总处理时间
     */
    public long getTotalProcessingTime() {
        return totalProcessingTime.get();
    }

    /**
     * 获取平均处理时间
     */
    public double getAverageProcessingTime() {
        int processed = successCount.get() + failureCount.get();
        return processed > 0 ? (double) totalProcessingTime.get() / processed : 0;
    }

    /**
     * 获取最小处理时间
     */
    public long getMinProcessingTime() {
        long min = minProcessingTime.get();
        return min == Long.MAX_VALUE ? 0 : min;
    }

    /**
     * 获取最大处理时间
     */
    public long getMaxProcessingTime() {
        return maxProcessingTime.get();
    }

    /**
     * 获取成功率
     */
    public double getSuccessRate() {
        int total = successCount.get() + failureCount.get();
        return total > 0 ? (double) successCount.get() / total * 100 : 0;
    }

    /**
     * 获取失败率
     */
    public double getFailureRate() {
        int total = successCount.get() + failureCount.get();
        return total > 0 ? (double) failureCount.get() / total * 100 : 0;
    }

    /**
     * 获取吞吐量（消息/分钟）
     */
    public double getThroughput() {
        long windowMinutes = ChronoUnit.MINUTES.between(windowStart, windowEnd);
        return windowMinutes > 0 ? (double) messageCount.get() / windowMinutes : 0;
    }

    /**
     * 检查窗口是否已过期
     */
    public boolean isExpired() {
        return LocalDateTime.now().isAfter(windowEnd);
    }

    private void updateMinProcessingTime(long time) {
        long current;
        do {
            current = minProcessingTime.get();
        } while (time < current && !minProcessingTime.compareAndSet(current, time));
    }

    private void updateMaxProcessingTime(long time) {
        long current;
        do {
            current = maxProcessingTime.get();
        } while (time > current && !maxProcessingTime.compareAndSet(current, time));
    }

    @Override
    public String toString() {
        return String.format(
                "TimeWindowStatistics{window=%s~%s, messages=%d, success=%d, failure=%d, " +
                "avgTime=%.2fms, successRate=%.1f%%, throughput=%.1f msg/min}",
                windowStart, windowEnd, messageCount.get(), successCount.get(),
                failureCount.get(), getAverageProcessingTime(), getSuccessRate(), getThroughput()
        );
    }

    /**
     * 获取详细报告
     */
    public String getDetailedReport() {
        StringBuilder report = new StringBuilder();
        report.append("=== 时间窗口统计报告 ===\n");
        report.append(String.format("时间窗口: %s ~ %s (%d 分钟)\n", windowStart, windowEnd, windowSizeMinutes));
        report.append(String.format("是否过期: %s\n", isExpired() ? "是" : "否"));
        report.append("\n消息统计:\n");
        report.append(String.format("  总消息数: %d\n", messageCount.get()));
        report.append(String.format("  成功处理: %d\n", successCount.get()));
        report.append(String.format("  处理失败: %d\n", failureCount.get()));

        report.append("\n性能指标:\n");
        report.append(String.format("  平均处理时间: %.2f ms\n", getAverageProcessingTime()));
        report.append(String.format("  处理时间范围: %d - %d ms\n", getMinProcessingTime(), getMaxProcessingTime()));
        report.append(String.format("  成功率: %.2f%%\n", getSuccessRate()));
        report.append(String.format("  失败率: %.2f%%\n", getFailureRate()));
        report.append(String.format("  吞吐量: %.2f 消息/分钟\n", getThroughput()));

        report.append("========================\n");
        return report.toString();
    }
}